#include <time.h>
#include <string.h>
#include <stdio.h>
#include "rtl876x_rtc.h"
#include "rtl876x_nvic.h"
#include "trace.h"

static volatile uint32_t overflow_cnt;
static time_t offset_time_in_sec;             /* Time passed since Unix epoch */
static const char * _month[] =  {  
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};

clock_t clock(void)
{
    return RTC_GetCounter();
}

time_t time(time_t *p_time)
{
    time_t seconds;
    /* seconds = (overflow_cnt * 2^24 + RTC_COUNT) / 1000 */
    seconds = ((overflow_cnt<<24) + clock()) / 1000;
    seconds += offset_time_in_sec;
    
    if ( p_time != NULL )
        *p_time = seconds;
    
    return seconds;
}

static int month2int( char * str )
{
    int i;
    for (i = 0; i < 12; i++)
        if (strcmp(_month[i], str) == 0)
            break;
    return i;
}

/**
  * @brief  RTC interrupt handle function.
  * @param  None.
  * @return None.
  */
void RTC_Handler(void)
{
    /* RTC overflow interrupt handle */
    if (RTC_GetINTStatus(RTC_INT_OVF) == SET)
    {
        /* Notes: DBG_DIRECT function is only used for debugging demonstrations, not for application projects.*/
        DBG_DIRECT("[main]RTC_Handler: RTC_INT_OVF");
        // Add application code here
        RTC_ClearOverFlowINT();
        
        overflow_cnt++;
    }
}

void time_init(struct tm * time_ptr) 
{
    if ( time_ptr == NULL ) {
        /* Use Compiled time as system init time. */
        char month_name[5];
        struct tm compiled_tm = {0};
        sscanf(__DATE__, "%s %d %d", month_name, &compiled_tm.tm_mday, &compiled_tm.tm_year);
        sscanf(__TIME__, "%d:%d:%d", &compiled_tm.tm_hour, &compiled_tm.tm_min, &compiled_tm.tm_sec);

        compiled_tm.tm_mon = month2int(month_name);
        compiled_tm.tm_year -= 1900;

        offset_time_in_sec = mktime(&compiled_tm) - 8 * 3600;  // compiled time is UTC+8
    } else {
        time_t current_time = time(NULL);
        time_t new_time     = mktime(time_ptr);
        if ( new_time > current_time )
            offset_time_in_sec += new_time - current_time;
        else
            offset_time_in_sec -= current_time - new_time;
    }
    
    RTC_DeInit();
    RTC_SetPrescaler(31);//f=1000Hz
    RTC_MaskINTConfig(RTC_INT_OVF, DISABLE);
    
    /* Config RTC interrupt */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    
    /* Start RTC */
    RTC_RunCmd(ENABLE);
}

void time_correction(time_t new_time)
{
    time_t current_time = time(NULL);

    if ( new_time > current_time )
        offset_time_in_sec += new_time - current_time;
    else
        offset_time_in_sec -= current_time - new_time;
}
